﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using Tridion.ContentManager.CoreService.Client;
using TridionDesktopTools.Core.Annotations;

namespace TridionDesktopTools.Core
{
    public class FieldMappingInfo : INotifyPropertyChanged
    {
        private ItemFieldDefinitionData _SourceField;
        private ItemFieldDefinitionData _TargetField;
        private string _DefaultValue;
        private string _TargetFolderUri;

        public List<ItemFieldDefinitionData> SourceSchemaFields { private get; set; }

        public ItemFieldDefinitionData SourceField
        {
            get { return _SourceField; }
            set
            {
                if (Equals(value, _SourceField)) return;
                _SourceField = value;
                OnPropertyChanged("SourceField");
                OnPropertyChanged("SourceFieldName");
                OnPropertyChanged("MappingAvailable");
                OnPropertyChanged("Valid");
            }
        }

        public ItemFieldDefinitionData TargetField
        {
            get { return _TargetField; }
            set
            {
                if (Equals(value, _TargetField)) return;
                _TargetField = value;
                OnPropertyChanged("TargetField");
                OnPropertyChanged("TargetFieldName");
                OnPropertyChanged("MappingAvailable");
                OnPropertyChanged("Valid");
            }
        }

        public string DefaultValue
        {
            get { return _DefaultValue; }
            set
            {
                if (value == _DefaultValue) return;
                _DefaultValue = value;
                OnPropertyChanged("DefaultValue");
                OnPropertyChanged("Valid");
            }
        }

        public string SourceFieldName
        {
            get
            {
                return this.SourceField == null || string.IsNullOrEmpty(this.SourceField.Name) ? "< ignore >" : this.SourceField.GetFieldFullName();
            }
            set
            {
                this.SourceField = this.SourceSchemaFields.FirstOrDefault(x => x.GetFieldFullName() == value);
                OnPropertyChanged("SourceField");
                OnPropertyChanged("SourceFieldName");
                OnPropertyChanged("MappingAvailable");
                OnPropertyChanged("Valid");
            }
        }

        public string TargetFolderUri
        {
            get { return _TargetFolderUri; }
            set
            {
                if (value == _TargetFolderUri) return;
                _TargetFolderUri = value;

                if (this.ChildFieldMapping != null)
                {
                    foreach (FieldMappingInfo childMapping in this.ChildFieldMapping)
                    {
                        childMapping.TargetFolderUri = _TargetFolderUri;
                    }
                }

                OnPropertyChanged("TargetFolderUri");
            }
        }

        public string TargetFieldName
        {
            get
            {
                return this.TargetField.GetFieldFullName();
            }
        }

        public List<FieldMappingInfo> ChildFieldMapping { get; set; }

        public string SourceFieldSchemaUri
        {
            get
            {
                if (this.SourceField.IsEmbedded())
                    return ((EmbeddedSchemaFieldDefinitionData) this.SourceField).EmbeddedSchema.IdRef;

                if (this.SourceField.IsComponentLink())
                {
                    ComponentLinkFieldDefinitionData field = ((ComponentLinkFieldDefinitionData) this.SourceField);
                    if (field.AllowedTargetSchemas.Any())
                        return field.AllowedTargetSchemas[0].IdRef;
                }

                return string.Empty;
            }
        }

        public string TargetFieldSchemaUri
        {
            get
            {
                if (this.TargetField.IsEmbedded())
                    return ((EmbeddedSchemaFieldDefinitionData)this.TargetField).EmbeddedSchema.IdRef;

                if (this.TargetField.IsComponentLink())
                {
                    ComponentLinkFieldDefinitionData field = ((ComponentLinkFieldDefinitionData)this.TargetField);
                    if (field.AllowedTargetSchemas.Any())
                        return field.AllowedTargetSchemas[0].IdRef;
                }

                return string.Empty;
            }
        }

        public Visibility MappingAvailable
        {
            get
            {
                if (this.SourceField == null || this.TargetField == null)
                    return Visibility.Hidden;

                if((this.SourceField.IsEmbedded() || this.SourceField.IsComponentLink()) &&
                    (this.TargetField.IsEmbedded() || this.TargetField.IsComponentLink()) &&
                    (this.SourceField.Name != this.TargetField.Name || this.SourceField.GetFieldType() != this.TargetField.GetFieldType() || this.SourceFieldSchemaUri != this.TargetFieldSchemaUri))
                    return Visibility.Visible;

                return Visibility.Hidden;
            }
        }

        public bool Valid
        {
            get
            {
                if (this.MappingAvailable == Visibility.Visible)
                    return true;

                if (this.TargetField.IsMandatory())
                    return this.SourceField != null || !String.IsNullOrEmpty(this.DefaultValue);

                return this.SourceField == null || this.SourceField.GetFieldTypeName() == this.TargetField.GetFieldTypeName();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
